{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 使用 Unsloth 对 DeepSeek-R1-Distill-Qwen-1.5B 模型进行 LoRA 微调\n",
    "\n",
    "本 Notebook 展示了如何使用 `unsloth` 库对 `deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B` 模型进行高效的 QLoRA (Low-Rank Adaptation) 微调。\n",
    "\n",
    "整个流程包括：\n",
    "1.  环境准备与库导入\n",
    "2.  加载预训练模型和分词器 (Tokenizer)。\n",
    "3.  在微调前，对模型进行简单的推理测试。\n",
    "4.  下载和格式化训练数据集\n",
    "5.  使用 `unsloth` 的 `FastLanguageModel` 来为模型添加 LoRA 适配器。\n",
    "6.  配置 `SFTTrainer` 监督微调训练配置。\n",
    "7.  启动训练，并观察 Loss 变化情况\n",
    "8.  保存微调后的模型\n",
    "9.  测试训练后的生成结果"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1. 环境准备与库导入\n",
    "\n",
    "首先，我们需要安装并导入所有必要的库。`transformers` 用于加载模型和分词器，`unsloth` 用于高效微调，`trl` 提供了 `SFTTrainer`，而 `datasets` 用于处理数据。\n",
    "\n",
    "**注意**: 在运行此 Notebook 之前，请确保已安装所有依赖包：\n",
    "```bash\n",
    "pip install -r requirements.txt\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "🦥 Unsloth: Will patch your computer to enable 2x faster free finetuning.\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/ubuntu/miniconda3/envs/qwenLora/lib/python3.13/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
      "  from .autonotebook import tqdm as notebook_tqdm\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "🦥 Unsloth Zoo will now patch everything to make training faster!\n"
     ]
    }
   ],
   "source": [
    "import torch\n",
    "from unsloth import FastLanguageModel\n",
    "from transformers import AutoTokenizer, AutoModelForCausalLM, BitsAndBytesConfig, GenerationConfig, DataCollatorForSeq2Seq\n",
    "from datasets import Dataset"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2. 加载预训练模型和分词器 (Tokenizer)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "==((====))==  Unsloth 2025.8.5: Fast Qwen2 patching. Transformers: 4.55.2.\n",
      "   \\\\   /|    Tesla T4. Num GPUs = 1. Max memory: 14.581 GB. Platform: Linux.\n",
      "O^O/ \\_/ \\    Torch: 2.7.1+cu126. CUDA: 7.5. CUDA Toolkit: 12.6. Triton: 3.3.1\n",
      "\\        /    Bfloat16 = FALSE. FA [Xformers = 0.0.31.post1. FA2 = False]\n",
      " \"-____-\"     Free license: http://github.com/unslothai/unsloth\n",
      "Unsloth: Fast downloading is enabled - ignore downloading bars which are red colored!\n"
     ]
    }
   ],
   "source": [
    "# 定义模型和一些基本参数\n",
    "max_seq_length = 8192\n",
    "dtype = None # None 表示自动选择 (Float16 a T4, V100, BFloat16 a Ampere)\n",
    "load_in_4bit = True # 使用 4bit 量化加载\n",
    "\n",
    "# 这是您的模型标识符，请替换为您正在使用的模型\n",
    "# 例如：\"qwen-1.5b_lora_model\"\n",
    "# model_name = \"qwen-1.5b_lora_model\" \n",
    "# model_name = \"unsloth/DeepSeek-R1-Distill-Qwen-1.5B\" \n",
    "model_name = \"unsloth/DeepSeek-R1-Distill-Qwen-1.5B-unsloth-bnb-4bit\" \n",
    "\n",
    "# 这一步会返回一个经过 Unsloth 优化的模型和一个分词器\n",
    "model, tokenizer = FastLanguageModel.from_pretrained(\n",
    "    model_name = model_name,\n",
    "    max_seq_length = max_seq_length,\n",
    "    dtype = dtype,\n",
    "    load_in_4bit = load_in_4bit,\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3. 微调前推理测试\n",
    "\n",
    "在对模型进行任何修改之前，我们先用它来生成一段文本，看看原始模型的表现如何。这可以作为我们微调效果的基准参考。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 模型推理的 Prompt 模板\n",
    "inference_prompt = \"\"\"以下是一条描述任务的指令，并配有一个提供进一步上下文的输入。\n",
    "请撰写一份恰当的回复，以完成该请求。\n",
    "在回答之前，请仔细思考该问题，并构建一个分步的思考过程，以确保回应的逻辑严谨和内容准确。\n",
    "\n",
    "\n",
    "### Instruction:\n",
    "你是一位医学专家，在临床推理、诊断学和治疗规划方面拥有深厚的专业知识。\n",
    "请回答以下医学问题。\n",
    "\n",
    "### Question:\n",
    "{}\n",
    "\n",
    "### Response:\n",
    "<think>{}\n",
    "\"\"\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "FastLanguageModel.for_inference(model)\n",
    "\n",
    "question = \"男，28岁，程序员，最近一周每天工作到半夜，感觉头晕、脖子疼，有时候还恶心。\"\n",
    "\n",
    "inputs = tokenizer([inference_prompt.format(question, \"\")], return_tensors=\"pt\").to(\"cuda\")\n",
    "attention_mask = inputs.input_ids.ne(tokenizer.pad_token_id).long().to(\"cuda\")\n",
    "\n",
    "outputs = model.generate(\n",
    "    input_ids=inputs.input_ids,\n",
    "    attention_mask=inputs.attention_mask,\n",
    "    max_new_tokens=1200,\n",
    "    use_cache=True,\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "response = tokenizer.batch_decode(outputs, skip_special_tokens=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "<think>\n",
      "好，我现在需要分析这位28岁的程序员近期的健康问题，以及如何帮助他恢复健康。首先，他工作到半夜，感觉头晕、脖子疼，还可能恶心。这些症状可能与长时间工作、压力或疲劳有关。由于是程序员，工作压力大，可能影响了身体健康。\n",
      "\n",
      "我应该考虑他的可能健康问题，比如脑力运动性脑损伤，或者疲劳性脑损伤。脑力运动性脑损伤通常涉及运动性脑损伤，可能与运动损伤有关，比如长时间站立、行走等，导致脑部损伤。疲劳性脑损伤可能是因为长期的工作导致的疲劳，但通常会伴随疼痛，而这里没有疼痛描述，只是感觉。所以可能需要进一步评估。\n",
      "\n",
      "接下来，我应该建议他寻求专业医疗帮助，比如眼科医生检查视力问题，因为头晕可能影响视力。如果是运动损伤，可能需要神经科医生进行检查，评估运动性脑损伤的严重性。如果他有其他症状，比如恶心，可能需要进一步观察是否有其他症状，如恶心、呕吐，或者意识模糊等。\n",
      "\n",
      "此外，我应该提醒他保持良好的休息和规律的作息，避免长时间的休息，因为长时间工作可能会影响神经功能。同时，建议他避免过度劳累，必要时休息一下，然后恢复。\n",
      "\n",
      "最后，我应该建议他立即联系专业医疗团队，进行详细的检查和诊断，以确保他得到及时的治疗和预防措施。如果有其他相关问题，比如视力问题或其他症状，也需要及时就医。\n",
      "</think>\n",
      "\n",
      "男，28岁，程序员，最近一周每天工作到半夜，感觉头晕、脖子疼，有时候还恶心。\n",
      "\n",
      "### 分步思考过程：\n",
      "\n",
      "1. **分析症状和背景**：\n",
      "   - 病人在工作到深夜，表现出头晕、脖子疼、恶心等症状。\n",
      "   - 这些症状可能与长时间工作、压力或疲劳有关。\n",
      "   - 由于是程序员，长期工作可能影响身体健康。\n",
      "\n",
      "2. **考虑可能的健康问题**：\n",
      "   - **脑力运动性脑损伤**：可能与长时间站立、行走有关，导致运动性脑损伤。\n",
      "   - **疲劳性脑损伤**：长期疲劳可能导致神经功能受损。\n",
      "   - **视力问题**：头晕可能影响视力，需要眼科医生评估。\n",
      "   - **其他症状**：恶心可能需要进一步观察是否有其他症状，如恶心、呕吐，或意识模糊。\n",
      "\n",
      "3. **建议的医疗建议**：\n",
      "   - **专业医疗团队**：立即联系眼科医生检查视力问题，必要时进行脑部影像学检查（如MRI或CT）评估运动性脑损伤。\n",
      "   - **休息和规律作息**：建议他保持良好的休息和规律的作息，避免长时间休息。\n",
      "   - **避免过度劳累**：必要时休息一下，然后恢复。\n",
      "   - **预防措施**：如进行适当的心理干预，保持良好的心态。\n",
      "\n",
      "4. **总结**：\n",
      "   - 病人可能有脑力运动性脑损伤或疲劳性脑损伤，需要及时就医。\n",
      "   - 病人应立即联系专业医疗团队进行检查和诊断，以确保其健康状况得到及时的评估和处理。\n",
      "\n",
      "### 最终回复：\n",
      "\n",
      "请立即联系专业医疗团队，包括眼科医生和神经科医生，进行详细检查和评估。建议他保持良好的休息和规律的作息，避免长时间劳累。如有其他相关症状或异常情况，请及时报告，以便获得更及时的诊断和治疗。\n"
     ]
    }
   ],
   "source": [
    "print(response[0].split(\"### Response:\")[1])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "### 4. 下载和格式化训练数据集\n",
    "\n",
    "\n",
    "医学推理数据集：https://huggingface.co/datasets/FreedomIntelligence/medical-o1-reasoning-SFT/viewer/zh\n",
    "\n",
    "![dataset](images/dataset.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 模型训练的 Prompt 模板\n",
    "train_prompt = \"\"\"以下是一条描述任务的指令，并配有一个提供进一步上下文的输入。\n",
    "请撰写一份恰当的回复，以完成该请求。\n",
    "在回答之前，请仔细思考该问题，并构建一个分步的思考过程，以确保回应的逻辑严谨和内容准确。\n",
    "\n",
    "\n",
    "### Instruction:\n",
    "你是一位医学专家，在临床推理、诊断学和治疗规划方面拥有深厚的专业知识。\n",
    "请回答以下医学问题。\n",
    "\n",
    "### Question:\n",
    "{}\n",
    "\n",
    "### Response:\n",
    "<think>\n",
    "{}\n",
    "</think>\n",
    "{}\n",
    "\"\"\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "EOS_TOKEN = tokenizer.eos_token # 添加 EOS Token\n",
    "\n",
    "def formatting_prompts_func(examples):\n",
    "    inputs = examples[\"Question\"]\n",
    "    cots = examples[\"Complex_CoT\"]\n",
    "    outputs = examples[\"Response\"]\n",
    "    texts = []\n",
    "    for input, cot, output in zip(inputs, cots, outputs):\n",
    "        # 将 EOS Token 添加到样本最后\n",
    "        text = train_prompt.format(input, cot, output) + EOS_TOKEN\n",
    "        texts.append(text)\n",
    "    return { \"text\" : texts, }\n",
    "pass\n",
    "\n",
    "from datasets import load_dataset\n",
    "dataset = load_dataset(\"FreedomIntelligence/medical-o1-reasoning-SFT\", \"zh\", split = \"train\")\n",
    "dataset = dataset.map(formatting_prompts_func, batched = True,)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'以下是一条描述任务的指令，并配有一个提供进一步上下文的输入。\\n请撰写一份恰当的回复，以完成该请求。\\n在回答之前，请仔细思考该问题，并构建一个分步的思考过程，以确保回应的逻辑严谨和内容准确。\\n\\n\\n### Instruction:\\n你是一位医学专家，在临床推理、诊断学和治疗规划方面拥有深厚的专业知识。\\n请回答以下医学问题。\\n\\n### Question:\\n根据描述，一个1岁的孩子在夏季头皮出现多处小结节，长期不愈合，且现在疮大如梅，溃破流脓，口不收敛，头皮下有空洞，患处皮肤增厚。这种病症在中医中诊断为什么病？\\n\\n### Response:\\n<think>\\n这个小孩子在夏天头皮上长了些小结节，一直都没好，后来变成了脓包，流了好多脓。想想夏天那么热，可能和湿热有关。才一岁的小孩，免疫力本来就不强，夏天的湿热没准就侵袭了身体。\\n\\n用中医的角度来看，出现小结节、再加上长期不愈合，这些症状让我想到了头疮。小孩子最容易得这些皮肤病，主要因为湿热在体表郁结。\\n\\n但再看看，头皮下还有空洞，这可能不止是简单的头疮。看起来病情挺严重的，也许是脓肿没治好。这样的情况中医中有时候叫做禿疮或者湿疮，也可能是另一种情况。\\n\\n等一下，头皮上的空洞和皮肤增厚更像是疾病已经深入到头皮下，这是不是说明有可能是流注或瘰疬？这些名字常描述头部或颈部的严重感染，特别是有化脓不愈合，又形成通道或空洞的情况。\\n\\n仔细想想，我怎么感觉这些症状更贴近瘰疬的表现？尤其考虑到孩子的年纪和夏天发生的季节性因素，湿热可能是主因，但可能也有火毒或者痰湿造成的滞留。\\n\\n回到基本的症状描述上看，这种长期不愈合又复杂的状况，如果结合中医更偏重的病名，是不是有可能是涉及更深层次的感染？\\n\\n再考虑一下，这应该不是单纯的瘰疬，得仔细分析头皮增厚并出现空洞这样的严重症状。中医里头，这样的表现可能更符合‘蚀疮’或‘头疽’。这些病名通常描述头部严重感染后的溃烂和组织坏死。\\n\\n看看季节和孩子的体质，夏天又湿又热，外邪很容易侵入头部，对孩子这么弱的免疫系统简直就是挑战。头疽这个病名听起来真是切合，因为它描述的感染严重，溃烂到出现空洞。\\n\\n不过，仔细琢磨后发现，还有个病名似乎更为合适，叫做‘蝼蛄疖’，这病在中医里专指像这种严重感染并伴有深部空洞的情况。它也涵盖了化脓和皮肤增厚这些症状。\\n\\n哦，该不会是夏季湿热，导致湿毒入侵，孩子的体质不能御，其病情发展成这样的感染？综合分析后我觉得‘蝼蛄疖’这个病名真是相当符合。\\n</think>\\n从中医的角度来看，你所描述的症状符合“蝼蛄疖”的病症。这种病症通常发生在头皮，表现为多处结节，溃破流脓，形成空洞，患处皮肤增厚且长期不愈合。湿热较重的夏季更容易导致这种病症的发展，特别是在免疫力较弱的儿童身上。建议结合中医的清热解毒、祛湿消肿的治疗方法进行处理，并配合专业的医疗建议进行详细诊断和治疗。\\n<｜end▁of▁sentence｜>'"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "dataset[0][\"text\"]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/markdown": [
       "以下是一条描述任务的指令，并配有一个提供进一步上下文的输入。\n",
       "请撰写一份恰当的回复，以完成该请求。\n",
       "在回答之前，请仔细思考该问题，并构建一个分步的思考过程，以确保回应的逻辑严谨和内容准确。\n",
       "\n",
       "\n",
       "### Instruction:\n",
       "你是一位医学专家，在临床推理、诊断学和治疗规划方面拥有深厚的专业知识。\n",
       "请回答以下医学问题。\n",
       "\n",
       "### Question:\n",
       "根据描述，一个1岁的孩子在夏季头皮出现多处小结节，长期不愈合，且现在疮大如梅，溃破流脓，口不收敛，头皮下有空洞，患处皮肤增厚。这种病症在中医中诊断为什么病？\n",
       "\n",
       "### Response:\n",
       "<think>\n",
       "这个小孩子在夏天头皮上长了些小结节，一直都没好，后来变成了脓包，流了好多脓。想想夏天那么热，可能和湿热有关。才一岁的小孩，免疫力本来就不强，夏天的湿热没准就侵袭了身体。\n",
       "\n",
       "用中医的角度来看，出现小结节、再加上长期不愈合，这些症状让我想到了头疮。小孩子最容易得这些皮肤病，主要因为湿热在体表郁结。\n",
       "\n",
       "但再看看，头皮下还有空洞，这可能不止是简单的头疮。看起来病情挺严重的，也许是脓肿没治好。这样的情况中医中有时候叫做禿疮或者湿疮，也可能是另一种情况。\n",
       "\n",
       "等一下，头皮上的空洞和皮肤增厚更像是疾病已经深入到头皮下，这是不是说明有可能是流注或瘰疬？这些名字常描述头部或颈部的严重感染，特别是有化脓不愈合，又形成通道或空洞的情况。\n",
       "\n",
       "仔细想想，我怎么感觉这些症状更贴近瘰疬的表现？尤其考虑到孩子的年纪和夏天发生的季节性因素，湿热可能是主因，但可能也有火毒或者痰湿造成的滞留。\n",
       "\n",
       "回到基本的症状描述上看，这种长期不愈合又复杂的状况，如果结合中医更偏重的病名，是不是有可能是涉及更深层次的感染？\n",
       "\n",
       "再考虑一下，这应该不是单纯的瘰疬，得仔细分析头皮增厚并出现空洞这样的严重症状。中医里头，这样的表现可能更符合‘蚀疮’或‘头疽’。这些病名通常描述头部严重感染后的溃烂和组织坏死。\n",
       "\n",
       "看看季节和孩子的体质，夏天又湿又热，外邪很容易侵入头部，对孩子这么弱的免疫系统简直就是挑战。头疽这个病名听起来真是切合，因为它描述的感染严重，溃烂到出现空洞。\n",
       "\n",
       "不过，仔细琢磨后发现，还有个病名似乎更为合适，叫做‘蝼蛄疖’，这病在中医里专指像这种严重感染并伴有深部空洞的情况。它也涵盖了化脓和皮肤增厚这些症状。\n",
       "\n",
       "哦，该不会是夏季湿热，导致湿毒入侵，孩子的体质不能御，其病情发展成这样的感染？综合分析后我觉得‘蝼蛄疖’这个病名真是相当符合。\n",
       "</think>\n",
       "从中医的角度来看，你所描述的症状符合“蝼蛄疖”的病症。这种病症通常发生在头皮，表现为多处结节，溃破流脓，形成空洞，患处皮肤增厚且长期不愈合。湿热较重的夏季更容易导致这种病症的发展，特别是在免疫力较弱的儿童身上。建议结合中医的清热解毒、祛湿消肿的治疗方法进行处理，并配合专业的医疗建议进行详细诊断和治疗。\n",
       "<｜end▁of▁sentence｜>"
      ],
      "text/plain": [
       "<IPython.core.display.Markdown object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from IPython.display import display, Markdown\n",
    "\n",
    "display(Markdown(dataset[0][\"text\"]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 5. 使用 Unsloth 添加 LoRA 适配器\n",
    "\n",
    "这是使用 `unsloth` 的核心步骤。我们调用 `FastLanguageModel.get_peft_model`，它会非常高效地为模型注入 LoRA 模块。\n",
    "\n",
    "- `r`: LoRA 的秩 (rank)，是控制模型复杂度和参数量的关键超参数。\n",
    "- `target_modules`: 指定要在哪些线性层（如注意力机制的 q, k, v, o 投影层）上应用 LoRA。\n",
    "- `lora_alpha`: LoRA 的缩放因子，通常设置为 `r` 的两倍或与 `r` 相同。\n",
    "- `use_gradient_checkpointing`: 一种节省显存的技术，对于训练大模型至关重要。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Unsloth 2025.8.5 patched 28 layers with 28 QKV layers, 28 O layers and 28 MLP layers.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "PeftModelForCausalLM(\n",
      "  (base_model): LoraModel(\n",
      "    (model): Qwen2ForCausalLM(\n",
      "      (model): Qwen2Model(\n",
      "        (embed_tokens): Embedding(151936, 1536, padding_idx=151654)\n",
      "        (layers): ModuleList(\n",
      "          (0): Qwen2DecoderLayer(\n",
      "            (self_attn): Qwen2Attention(\n",
      "              (q_proj): lora.Linear(\n",
      "                (base_layer): Linear(in_features=1536, out_features=1536, bias=True)\n",
      "                (lora_dropout): ModuleDict(\n",
      "                  (default): Identity()\n",
      "                )\n",
      "                (lora_A): ModuleDict(\n",
      "                  (default): Linear(in_features=1536, out_features=16, bias=False)\n",
      "                )\n",
      "                (lora_B): ModuleDict(\n",
      "                  (default): Linear(in_features=16, out_features=1536, bias=False)\n",
      "                )\n",
      "                (lora_embedding_A): ParameterDict()\n",
      "                (lora_embedding_B): ParameterDict()\n",
      "                (lora_magnitude_vector): ModuleDict()\n",
      "              )\n",
      "              (k_proj): lora.Linear(\n",
      "                (base_layer): Linear(in_features=1536, out_features=256, bias=True)\n",
      "                (lora_dropout): ModuleDict(\n",
      "                  (default): Identity()\n",
      "                )\n",
      "                (lora_A): ModuleDict(\n",
      "                  (default): Linear(in_features=1536, out_features=16, bias=False)\n",
      "                )\n",
      "                (lora_B): ModuleDict(\n",
      "                  (default): Linear(in_features=16, out_features=256, bias=False)\n",
      "                )\n",
      "                (lora_embedding_A): ParameterDict()\n",
      "                (lora_embedding_B): ParameterDict()\n",
      "                (lora_magnitude_vector): ModuleDict()\n",
      "              )\n",
      "              (v_proj): lora.Linear(\n",
      "                (base_layer): Linear(in_features=1536, out_features=256, bias=True)\n",
      "                (lora_dropout): ModuleDict(\n",
      "                  (default): Identity()\n",
      "                )\n",
      "                (lora_A): ModuleDict(\n",
      "                  (default): Linear(in_features=1536, out_features=16, bias=False)\n",
      "                )\n",
      "                (lora_B): ModuleDict(\n",
      "                  (default): Linear(in_features=16, out_features=256, bias=False)\n",
      "                )\n",
      "                (lora_embedding_A): ParameterDict()\n",
      "                (lora_embedding_B): ParameterDict()\n",
      "                (lora_magnitude_vector): ModuleDict()\n",
      "              )\n",
      "              (o_proj): lora.Linear(\n",
      "                (base_layer): Linear(in_features=1536, out_features=1536, bias=False)\n",
      "                (lora_dropout): ModuleDict(\n",
      "                  (default): Identity()\n",
      "                )\n",
      "                (lora_A): ModuleDict(\n",
      "                  (default): Linear(in_features=1536, out_features=16, bias=False)\n",
      "                )\n",
      "                (lora_B): ModuleDict(\n",
      "                  (default): Linear(in_features=16, out_features=1536, bias=False)\n",
      "                )\n",
      "                (lora_embedding_A): ParameterDict()\n",
      "                (lora_embedding_B): ParameterDict()\n",
      "                (lora_magnitude_vector): ModuleDict()\n",
      "              )\n",
      "              (rotary_emb): LlamaRotaryEmbedding()\n",
      "            )\n",
      "            (mlp): Qwen2MLP(\n",
      "              (gate_proj): lora.Linear4bit(\n",
      "                (base_layer): Linear4bit(in_features=1536, out_features=8960, bias=False)\n",
      "                (lora_dropout): ModuleDict(\n",
      "                  (default): Identity()\n",
      "                )\n",
      "                (lora_A): ModuleDict(\n",
      "                  (default): Linear(in_features=1536, out_features=16, bias=False)\n",
      "                )\n",
      "                (lora_B): ModuleDict(\n",
      "                  (default): Linear(in_features=16, out_features=8960, bias=False)\n",
      "                )\n",
      "                (lora_embedding_A): ParameterDict()\n",
      "                (lora_embedding_B): ParameterDict()\n",
      "                (lora_magnitude_vector): ModuleDict()\n",
      "              )\n",
      "              (up_proj): lora.Linear4bit(\n",
      "                (base_layer): Linear4bit(in_features=1536, out_features=8960, bias=False)\n",
      "                (lora_dropout): ModuleDict(\n",
      "                  (default): Identity()\n",
      "                )\n",
      "                (lora_A): ModuleDict(\n",
      "                  (default): Linear(in_features=1536, out_features=16, bias=False)\n",
      "                )\n",
      "                (lora_B): ModuleDict(\n",
      "                  (default): Linear(in_features=16, out_features=8960, bias=False)\n",
      "                )\n",
      "                (lora_embedding_A): ParameterDict()\n",
      "                (lora_embedding_B): ParameterDict()\n",
      "                (lora_magnitude_vector): ModuleDict()\n",
      "              )\n",
      "              (down_proj): lora.Linear4bit(\n",
      "                (base_layer): Linear4bit(in_features=8960, out_features=1536, bias=False)\n",
      "                (lora_dropout): ModuleDict(\n",
      "                  (default): Identity()\n",
      "                )\n",
      "                (lora_A): ModuleDict(\n",
      "                  (default): Linear(in_features=8960, out_features=16, bias=False)\n",
      "                )\n",
      "                (lora_B): ModuleDict(\n",
      "                  (default): Linear(in_features=16, out_features=1536, bias=False)\n",
      "                )\n",
      "                (lora_embedding_A): ParameterDict()\n",
      "                (lora_embedding_B): ParameterDict()\n",
      "                (lora_magnitude_vector): ModuleDict()\n",
      "              )\n",
      "              (act_fn): SiLU()\n",
      "            )\n",
      "            (input_layernorm): Qwen2RMSNorm((1536,), eps=1e-06)\n",
      "            (post_attention_layernorm): Qwen2RMSNorm((1536,), eps=1e-06)\n",
      "          )\n",
      "          (1-2): 2 x Qwen2DecoderLayer(\n",
      "            (self_attn): Qwen2Attention(\n",
      "              (q_proj): lora.Linear4bit(\n",
      "                (base_layer): Linear4bit(in_features=1536, out_features=1536, bias=True)\n",
      "                (lora_dropout): ModuleDict(\n",
      "                  (default): Identity()\n",
      "                )\n",
      "                (lora_A): ModuleDict(\n",
      "                  (default): Linear(in_features=1536, out_features=16, bias=False)\n",
      "                )\n",
      "                (lora_B): ModuleDict(\n",
      "                  (default): Linear(in_features=16, out_features=1536, bias=False)\n",
      "                )\n",
      "                (lora_embedding_A): ParameterDict()\n",
      "                (lora_embedding_B): ParameterDict()\n",
      "                (lora_magnitude_vector): ModuleDict()\n",
      "              )\n",
      "              (k_proj): lora.Linear4bit(\n",
      "                (base_layer): Linear4bit(in_features=1536, out_features=256, bias=True)\n",
      "                (lora_dropout): ModuleDict(\n",
      "                  (default): Identity()\n",
      "                )\n",
      "                (lora_A): ModuleDict(\n",
      "                  (default): Linear(in_features=1536, out_features=16, bias=False)\n",
      "                )\n",
      "                (lora_B): ModuleDict(\n",
      "                  (default): Linear(in_features=16, out_features=256, bias=False)\n",
      "                )\n",
      "                (lora_embedding_A): ParameterDict()\n",
      "                (lora_embedding_B): ParameterDict()\n",
      "                (lora_magnitude_vector): ModuleDict()\n",
      "              )\n",
      "              (v_proj): lora.Linear4bit(\n",
      "                (base_layer): Linear4bit(in_features=1536, out_features=256, bias=True)\n",
      "                (lora_dropout): ModuleDict(\n",
      "                  (default): Identity()\n",
      "                )\n",
      "                (lora_A): ModuleDict(\n",
      "                  (default): Linear(in_features=1536, out_features=16, bias=False)\n",
      "                )\n",
      "                (lora_B): ModuleDict(\n",
      "                  (default): Linear(in_features=16, out_features=256, bias=False)\n",
      "                )\n",
      "                (lora_embedding_A): ParameterDict()\n",
      "                (lora_embedding_B): ParameterDict()\n",
      "                (lora_magnitude_vector): ModuleDict()\n",
      "              )\n",
      "              (o_proj): lora.Linear4bit(\n",
      "                (base_layer): Linear4bit(in_features=1536, out_features=1536, bias=False)\n",
      "                (lora_dropout): ModuleDict(\n",
      "                  (default): Identity()\n",
      "                )\n",
      "                (lora_A): ModuleDict(\n",
      "                  (default): Linear(in_features=1536, out_features=16, bias=False)\n",
      "                )\n",
      "                (lora_B): ModuleDict(\n",
      "                  (default): Linear(in_features=16, out_features=1536, bias=False)\n",
      "                )\n",
      "                (lora_embedding_A): ParameterDict()\n",
      "                (lora_embedding_B): ParameterDict()\n",
      "                (lora_magnitude_vector): ModuleDict()\n",
      "              )\n",
      "              (rotary_emb): LlamaRotaryEmbedding()\n",
      "            )\n",
      "            (mlp): Qwen2MLP(\n",
      "              (gate_proj): lora.Linear(\n",
      "                (base_layer): Linear(in_features=1536, out_features=8960, bias=False)\n",
      "                (lora_dropout): ModuleDict(\n",
      "                  (default): Identity()\n",
      "                )\n",
      "                (lora_A): ModuleDict(\n",
      "                  (default): Linear(in_features=1536, out_features=16, bias=False)\n",
      "                )\n",
      "                (lora_B): ModuleDict(\n",
      "                  (default): Linear(in_features=16, out_features=8960, bias=False)\n",
      "                )\n",
      "                (lora_embedding_A): ParameterDict()\n",
      "                (lora_embedding_B): ParameterDict()\n",
      "                (lora_magnitude_vector): ModuleDict()\n",
      "              )\n",
      "              (up_proj): lora.Linear(\n",
      "                (base_layer): Linear(in_features=1536, out_features=8960, bias=False)\n",
      "                (lora_dropout): ModuleDict(\n",
      "                  (default): Identity()\n",
      "                )\n",
      "                (lora_A): ModuleDict(\n",
      "                  (default): Linear(in_features=1536, out_features=16, bias=False)\n",
      "                )\n",
      "                (lora_B): ModuleDict(\n",
      "                  (default): Linear(in_features=16, out_features=8960, bias=False)\n",
      "                )\n",
      "                (lora_embedding_A): ParameterDict()\n",
      "                (lora_embedding_B): ParameterDict()\n",
      "                (lora_magnitude_vector): ModuleDict()\n",
      "              )\n",
      "              (down_proj): lora.Linear(\n",
      "                (base_layer): Linear(in_features=8960, out_features=1536, bias=False)\n",
      "                (lora_dropout): ModuleDict(\n",
      "                  (default): Identity()\n",
      "                )\n",
      "                (lora_A): ModuleDict(\n",
      "                  (default): Linear(in_features=8960, out_features=16, bias=False)\n",
      "                )\n",
      "                (lora_B): ModuleDict(\n",
      "                  (default): Linear(in_features=16, out_features=1536, bias=False)\n",
      "                )\n",
      "                (lora_embedding_A): ParameterDict()\n",
      "                (lora_embedding_B): ParameterDict()\n",
      "                (lora_magnitude_vector): ModuleDict()\n",
      "              )\n",
      "              (act_fn): SiLU()\n",
      "            )\n",
      "            (input_layernorm): Qwen2RMSNorm((1536,), eps=1e-06)\n",
      "            (post_attention_layernorm): Qwen2RMSNorm((1536,), eps=1e-06)\n",
      "          )\n",
      "          (3-25): 23 x Qwen2DecoderLayer(\n",
      "            (self_attn): Qwen2Attention(\n",
      "              (q_proj): lora.Linear4bit(\n",
      "                (base_layer): Linear4bit(in_features=1536, out_features=1536, bias=True)\n",
      "                (lora_dropout): ModuleDict(\n",
      "                  (default): Identity()\n",
      "                )\n",
      "                (lora_A): ModuleDict(\n",
      "                  (default): Linear(in_features=1536, out_features=16, bias=False)\n",
      "                )\n",
      "                (lora_B): ModuleDict(\n",
      "                  (default): Linear(in_features=16, out_features=1536, bias=False)\n",
      "                )\n",
      "                (lora_embedding_A): ParameterDict()\n",
      "                (lora_embedding_B): ParameterDict()\n",
      "                (lora_magnitude_vector): ModuleDict()\n",
      "              )\n",
      "              (k_proj): lora.Linear4bit(\n",
      "                (base_layer): Linear4bit(in_features=1536, out_features=256, bias=True)\n",
      "                (lora_dropout): ModuleDict(\n",
      "                  (default): Identity()\n",
      "                )\n",
      "                (lora_A): ModuleDict(\n",
      "                  (default): Linear(in_features=1536, out_features=16, bias=False)\n",
      "                )\n",
      "                (lora_B): ModuleDict(\n",
      "                  (default): Linear(in_features=16, out_features=256, bias=False)\n",
      "                )\n",
      "                (lora_embedding_A): ParameterDict()\n",
      "                (lora_embedding_B): ParameterDict()\n",
      "                (lora_magnitude_vector): ModuleDict()\n",
      "              )\n",
      "              (v_proj): lora.Linear4bit(\n",
      "                (base_layer): Linear4bit(in_features=1536, out_features=256, bias=True)\n",
      "                (lora_dropout): ModuleDict(\n",
      "                  (default): Identity()\n",
      "                )\n",
      "                (lora_A): ModuleDict(\n",
      "                  (default): Linear(in_features=1536, out_features=16, bias=False)\n",
      "                )\n",
      "                (lora_B): ModuleDict(\n",
      "                  (default): Linear(in_features=16, out_features=256, bias=False)\n",
      "                )\n",
      "                (lora_embedding_A): ParameterDict()\n",
      "                (lora_embedding_B): ParameterDict()\n",
      "                (lora_magnitude_vector): ModuleDict()\n",
      "              )\n",
      "              (o_proj): lora.Linear4bit(\n",
      "                (base_layer): Linear4bit(in_features=1536, out_features=1536, bias=False)\n",
      "                (lora_dropout): ModuleDict(\n",
      "                  (default): Identity()\n",
      "                )\n",
      "                (lora_A): ModuleDict(\n",
      "                  (default): Linear(in_features=1536, out_features=16, bias=False)\n",
      "                )\n",
      "                (lora_B): ModuleDict(\n",
      "                  (default): Linear(in_features=16, out_features=1536, bias=False)\n",
      "                )\n",
      "                (lora_embedding_A): ParameterDict()\n",
      "                (lora_embedding_B): ParameterDict()\n",
      "                (lora_magnitude_vector): ModuleDict()\n",
      "              )\n",
      "              (rotary_emb): LlamaRotaryEmbedding()\n",
      "            )\n",
      "            (mlp): Qwen2MLP(\n",
      "              (gate_proj): lora.Linear4bit(\n",
      "                (base_layer): Linear4bit(in_features=1536, out_features=8960, bias=False)\n",
      "                (lora_dropout): ModuleDict(\n",
      "                  (default): Identity()\n",
      "                )\n",
      "                (lora_A): ModuleDict(\n",
      "                  (default): Linear(in_features=1536, out_features=16, bias=False)\n",
      "                )\n",
      "                (lora_B): ModuleDict(\n",
      "                  (default): Linear(in_features=16, out_features=8960, bias=False)\n",
      "                )\n",
      "                (lora_embedding_A): ParameterDict()\n",
      "                (lora_embedding_B): ParameterDict()\n",
      "                (lora_magnitude_vector): ModuleDict()\n",
      "              )\n",
      "              (up_proj): lora.Linear4bit(\n",
      "                (base_layer): Linear4bit(in_features=1536, out_features=8960, bias=False)\n",
      "                (lora_dropout): ModuleDict(\n",
      "                  (default): Identity()\n",
      "                )\n",
      "                (lora_A): ModuleDict(\n",
      "                  (default): Linear(in_features=1536, out_features=16, bias=False)\n",
      "                )\n",
      "                (lora_B): ModuleDict(\n",
      "                  (default): Linear(in_features=16, out_features=8960, bias=False)\n",
      "                )\n",
      "                (lora_embedding_A): ParameterDict()\n",
      "                (lora_embedding_B): ParameterDict()\n",
      "                (lora_magnitude_vector): ModuleDict()\n",
      "              )\n",
      "              (down_proj): lora.Linear4bit(\n",
      "                (base_layer): Linear4bit(in_features=8960, out_features=1536, bias=False)\n",
      "                (lora_dropout): ModuleDict(\n",
      "                  (default): Identity()\n",
      "                )\n",
      "                (lora_A): ModuleDict(\n",
      "                  (default): Linear(in_features=8960, out_features=16, bias=False)\n",
      "                )\n",
      "                (lora_B): ModuleDict(\n",
      "                  (default): Linear(in_features=16, out_features=1536, bias=False)\n",
      "                )\n",
      "                (lora_embedding_A): ParameterDict()\n",
      "                (lora_embedding_B): ParameterDict()\n",
      "                (lora_magnitude_vector): ModuleDict()\n",
      "              )\n",
      "              (act_fn): SiLU()\n",
      "            )\n",
      "            (input_layernorm): Qwen2RMSNorm((1536,), eps=1e-06)\n",
      "            (post_attention_layernorm): Qwen2RMSNorm((1536,), eps=1e-06)\n",
      "          )\n",
      "          (26): Qwen2DecoderLayer(\n",
      "            (self_attn): Qwen2Attention(\n",
      "              (q_proj): lora.Linear4bit(\n",
      "                (base_layer): Linear4bit(in_features=1536, out_features=1536, bias=True)\n",
      "                (lora_dropout): ModuleDict(\n",
      "                  (default): Identity()\n",
      "                )\n",
      "                (lora_A): ModuleDict(\n",
      "                  (default): Linear(in_features=1536, out_features=16, bias=False)\n",
      "                )\n",
      "                (lora_B): ModuleDict(\n",
      "                  (default): Linear(in_features=16, out_features=1536, bias=False)\n",
      "                )\n",
      "                (lora_embedding_A): ParameterDict()\n",
      "                (lora_embedding_B): ParameterDict()\n",
      "                (lora_magnitude_vector): ModuleDict()\n",
      "              )\n",
      "              (k_proj): lora.Linear4bit(\n",
      "                (base_layer): Linear4bit(in_features=1536, out_features=256, bias=True)\n",
      "                (lora_dropout): ModuleDict(\n",
      "                  (default): Identity()\n",
      "                )\n",
      "                (lora_A): ModuleDict(\n",
      "                  (default): Linear(in_features=1536, out_features=16, bias=False)\n",
      "                )\n",
      "                (lora_B): ModuleDict(\n",
      "                  (default): Linear(in_features=16, out_features=256, bias=False)\n",
      "                )\n",
      "                (lora_embedding_A): ParameterDict()\n",
      "                (lora_embedding_B): ParameterDict()\n",
      "                (lora_magnitude_vector): ModuleDict()\n",
      "              )\n",
      "              (v_proj): lora.Linear4bit(\n",
      "                (base_layer): Linear4bit(in_features=1536, out_features=256, bias=True)\n",
      "                (lora_dropout): ModuleDict(\n",
      "                  (default): Identity()\n",
      "                )\n",
      "                (lora_A): ModuleDict(\n",
      "                  (default): Linear(in_features=1536, out_features=16, bias=False)\n",
      "                )\n",
      "                (lora_B): ModuleDict(\n",
      "                  (default): Linear(in_features=16, out_features=256, bias=False)\n",
      "                )\n",
      "                (lora_embedding_A): ParameterDict()\n",
      "                (lora_embedding_B): ParameterDict()\n",
      "                (lora_magnitude_vector): ModuleDict()\n",
      "              )\n",
      "              (o_proj): lora.Linear4bit(\n",
      "                (base_layer): Linear4bit(in_features=1536, out_features=1536, bias=False)\n",
      "                (lora_dropout): ModuleDict(\n",
      "                  (default): Identity()\n",
      "                )\n",
      "                (lora_A): ModuleDict(\n",
      "                  (default): Linear(in_features=1536, out_features=16, bias=False)\n",
      "                )\n",
      "                (lora_B): ModuleDict(\n",
      "                  (default): Linear(in_features=16, out_features=1536, bias=False)\n",
      "                )\n",
      "                (lora_embedding_A): ParameterDict()\n",
      "                (lora_embedding_B): ParameterDict()\n",
      "                (lora_magnitude_vector): ModuleDict()\n",
      "              )\n",
      "              (rotary_emb): LlamaRotaryEmbedding()\n",
      "            )\n",
      "            (mlp): Qwen2MLP(\n",
      "              (gate_proj): lora.Linear(\n",
      "                (base_layer): Linear(in_features=1536, out_features=8960, bias=False)\n",
      "                (lora_dropout): ModuleDict(\n",
      "                  (default): Identity()\n",
      "                )\n",
      "                (lora_A): ModuleDict(\n",
      "                  (default): Linear(in_features=1536, out_features=16, bias=False)\n",
      "                )\n",
      "                (lora_B): ModuleDict(\n",
      "                  (default): Linear(in_features=16, out_features=8960, bias=False)\n",
      "                )\n",
      "                (lora_embedding_A): ParameterDict()\n",
      "                (lora_embedding_B): ParameterDict()\n",
      "                (lora_magnitude_vector): ModuleDict()\n",
      "              )\n",
      "              (up_proj): lora.Linear(\n",
      "                (base_layer): Linear(in_features=1536, out_features=8960, bias=False)\n",
      "                (lora_dropout): ModuleDict(\n",
      "                  (default): Identity()\n",
      "                )\n",
      "                (lora_A): ModuleDict(\n",
      "                  (default): Linear(in_features=1536, out_features=16, bias=False)\n",
      "                )\n",
      "                (lora_B): ModuleDict(\n",
      "                  (default): Linear(in_features=16, out_features=8960, bias=False)\n",
      "                )\n",
      "                (lora_embedding_A): ParameterDict()\n",
      "                (lora_embedding_B): ParameterDict()\n",
      "                (lora_magnitude_vector): ModuleDict()\n",
      "              )\n",
      "              (down_proj): lora.Linear(\n",
      "                (base_layer): Linear(in_features=8960, out_features=1536, bias=False)\n",
      "                (lora_dropout): ModuleDict(\n",
      "                  (default): Identity()\n",
      "                )\n",
      "                (lora_A): ModuleDict(\n",
      "                  (default): Linear(in_features=8960, out_features=16, bias=False)\n",
      "                )\n",
      "                (lora_B): ModuleDict(\n",
      "                  (default): Linear(in_features=16, out_features=1536, bias=False)\n",
      "                )\n",
      "                (lora_embedding_A): ParameterDict()\n",
      "                (lora_embedding_B): ParameterDict()\n",
      "                (lora_magnitude_vector): ModuleDict()\n",
      "              )\n",
      "              (act_fn): SiLU()\n",
      "            )\n",
      "            (input_layernorm): Qwen2RMSNorm((1536,), eps=1e-06)\n",
      "            (post_attention_layernorm): Qwen2RMSNorm((1536,), eps=1e-06)\n",
      "          )\n",
      "          (27): Qwen2DecoderLayer(\n",
      "            (self_attn): Qwen2Attention(\n",
      "              (q_proj): lora.Linear4bit(\n",
      "                (base_layer): Linear4bit(in_features=1536, out_features=1536, bias=True)\n",
      "                (lora_dropout): ModuleDict(\n",
      "                  (default): Identity()\n",
      "                )\n",
      "                (lora_A): ModuleDict(\n",
      "                  (default): Linear(in_features=1536, out_features=16, bias=False)\n",
      "                )\n",
      "                (lora_B): ModuleDict(\n",
      "                  (default): Linear(in_features=16, out_features=1536, bias=False)\n",
      "                )\n",
      "                (lora_embedding_A): ParameterDict()\n",
      "                (lora_embedding_B): ParameterDict()\n",
      "                (lora_magnitude_vector): ModuleDict()\n",
      "              )\n",
      "              (k_proj): lora.Linear4bit(\n",
      "                (base_layer): Linear4bit(in_features=1536, out_features=256, bias=True)\n",
      "                (lora_dropout): ModuleDict(\n",
      "                  (default): Identity()\n",
      "                )\n",
      "                (lora_A): ModuleDict(\n",
      "                  (default): Linear(in_features=1536, out_features=16, bias=False)\n",
      "                )\n",
      "                (lora_B): ModuleDict(\n",
      "                  (default): Linear(in_features=16, out_features=256, bias=False)\n",
      "                )\n",
      "                (lora_embedding_A): ParameterDict()\n",
      "                (lora_embedding_B): ParameterDict()\n",
      "                (lora_magnitude_vector): ModuleDict()\n",
      "              )\n",
      "              (v_proj): lora.Linear4bit(\n",
      "                (base_layer): Linear4bit(in_features=1536, out_features=256, bias=True)\n",
      "                (lora_dropout): ModuleDict(\n",
      "                  (default): Identity()\n",
      "                )\n",
      "                (lora_A): ModuleDict(\n",
      "                  (default): Linear(in_features=1536, out_features=16, bias=False)\n",
      "                )\n",
      "                (lora_B): ModuleDict(\n",
      "                  (default): Linear(in_features=16, out_features=256, bias=False)\n",
      "                )\n",
      "                (lora_embedding_A): ParameterDict()\n",
      "                (lora_embedding_B): ParameterDict()\n",
      "                (lora_magnitude_vector): ModuleDict()\n",
      "              )\n",
      "              (o_proj): lora.Linear(\n",
      "                (base_layer): Linear(in_features=1536, out_features=1536, bias=False)\n",
      "                (lora_dropout): ModuleDict(\n",
      "                  (default): Identity()\n",
      "                )\n",
      "                (lora_A): ModuleDict(\n",
      "                  (default): Linear(in_features=1536, out_features=16, bias=False)\n",
      "                )\n",
      "                (lora_B): ModuleDict(\n",
      "                  (default): Linear(in_features=16, out_features=1536, bias=False)\n",
      "                )\n",
      "                (lora_embedding_A): ParameterDict()\n",
      "                (lora_embedding_B): ParameterDict()\n",
      "                (lora_magnitude_vector): ModuleDict()\n",
      "              )\n",
      "              (rotary_emb): LlamaRotaryEmbedding()\n",
      "            )\n",
      "            (mlp): Qwen2MLP(\n",
      "              (gate_proj): lora.Linear4bit(\n",
      "                (base_layer): Linear4bit(in_features=1536, out_features=8960, bias=False)\n",
      "                (lora_dropout): ModuleDict(\n",
      "                  (default): Identity()\n",
      "                )\n",
      "                (lora_A): ModuleDict(\n",
      "                  (default): Linear(in_features=1536, out_features=16, bias=False)\n",
      "                )\n",
      "                (lora_B): ModuleDict(\n",
      "                  (default): Linear(in_features=16, out_features=8960, bias=False)\n",
      "                )\n",
      "                (lora_embedding_A): ParameterDict()\n",
      "                (lora_embedding_B): ParameterDict()\n",
      "                (lora_magnitude_vector): ModuleDict()\n",
      "              )\n",
      "              (up_proj): lora.Linear4bit(\n",
      "                (base_layer): Linear4bit(in_features=1536, out_features=8960, bias=False)\n",
      "                (lora_dropout): ModuleDict(\n",
      "                  (default): Identity()\n",
      "                )\n",
      "                (lora_A): ModuleDict(\n",
      "                  (default): Linear(in_features=1536, out_features=16, bias=False)\n",
      "                )\n",
      "                (lora_B): ModuleDict(\n",
      "                  (default): Linear(in_features=16, out_features=8960, bias=False)\n",
      "                )\n",
      "                (lora_embedding_A): ParameterDict()\n",
      "                (lora_embedding_B): ParameterDict()\n",
      "                (lora_magnitude_vector): ModuleDict()\n",
      "              )\n",
      "              (down_proj): lora.Linear4bit(\n",
      "                (base_layer): Linear4bit(in_features=8960, out_features=1536, bias=False)\n",
      "                (lora_dropout): ModuleDict(\n",
      "                  (default): Identity()\n",
      "                )\n",
      "                (lora_A): ModuleDict(\n",
      "                  (default): Linear(in_features=8960, out_features=16, bias=False)\n",
      "                )\n",
      "                (lora_B): ModuleDict(\n",
      "                  (default): Linear(in_features=16, out_features=1536, bias=False)\n",
      "                )\n",
      "                (lora_embedding_A): ParameterDict()\n",
      "                (lora_embedding_B): ParameterDict()\n",
      "                (lora_magnitude_vector): ModuleDict()\n",
      "              )\n",
      "              (act_fn): SiLU()\n",
      "            )\n",
      "            (input_layernorm): Qwen2RMSNorm((1536,), eps=1e-06)\n",
      "            (post_attention_layernorm): Qwen2RMSNorm((1536,), eps=1e-06)\n",
      "          )\n",
      "        )\n",
      "        (norm): Qwen2RMSNorm((1536,), eps=1e-06)\n",
      "        (rotary_emb): LlamaRotaryEmbedding()\n",
      "      )\n",
      "      (lm_head): Linear(in_features=1536, out_features=151936, bias=False)\n",
      "    )\n",
      "  )\n",
      ")\n"
     ]
    }
   ],
   "source": [
    "# 因为 `model` 对象现在是由 Unsloth 创建的，它包含了所有必需的属性\n",
    "model = FastLanguageModel.get_peft_model(\n",
    "    model,\n",
    "    r=16,\n",
    "    target_modules=[\n",
    "      \"q_proj\",\n",
    "      \"k_proj\",\n",
    "      \"v_proj\",\n",
    "      \"o_proj\",\n",
    "      \"gate_proj\",\n",
    "      \"up_proj\",\n",
    "      \"down_proj\",\n",
    "    ],\n",
    "    lora_alpha=16,\n",
    "    lora_dropout=0,\n",
    "    bias=\"none\",\n",
    "    use_gradient_checkpointing=\"unsloth\",\n",
    "    random_state=1432,\n",
    "    use_rslora=False,\n",
    "    loftq_config=None,\n",
    ")\n",
    "# 检查模型结构，确认 LoRA 适配器已添加\n",
    "print(model)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 6. 配置 SFTTrainer\n",
    "\n",
    "`SFTTrainer` (Supervised Fine-tuning Trainer) 是一个专门用于指令微调的训练器。我们需要配置 `TrainingArguments` 来指定所有的训练参数，如批量大小、学习率、优化器等。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Detected kernel version 5.4.0, which is below the recommended minimum of 5.5.0; this can cause the process to hang. It is recommended to upgrade the kernel to the minimum version or higher.\n"
     ]
    }
   ],
   "source": [
    "from trl import SFTConfig, SFTTrainer\n",
    "trainer = SFTTrainer(\n",
    "    model = model,\n",
    "    tokenizer = tokenizer,\n",
    "    train_dataset = dataset,\n",
    "    dataset_text_field = \"text\",\n",
    "    max_seq_length = max_seq_length,\n",
    "    packing = False, # Can make training 5x faster for short sequences.\n",
    "    args = SFTConfig(\n",
    "        per_device_train_batch_size = 64,\n",
    "        gradient_accumulation_steps = 2,\n",
    "        warmup_steps = 5,\n",
    "        # num_train_epochs = 1, # Set this for 1 full training run.\n",
    "        max_steps = 60,\n",
    "        learning_rate = 2e-4,\n",
    "        logging_steps = 1,\n",
    "        optim = \"adamw_torch\",\n",
    "        weight_decay = 0.01,\n",
    "        lr_scheduler_type = \"linear\",\n",
    "        seed = 1432,\n",
    "        output_dir = \"outputs\",\n",
    "        report_to = \"none\", # Use this for WandB etc\n",
    "    ),\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 7. 开始训练\n",
    "\n",
    "一切准备就绪后，调用 `trainer.train()` 即可开始微调过程。训练结束后，会返回包含训练统计信息（如训练损失）的对象。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "==((====))==  Unsloth - 2x faster free finetuning | Num GPUs used = 1\n",
      "   \\\\   /|    Num examples = 20,171 | Num Epochs = 1 | Total steps = 60\n",
      "O^O/ \\_/ \\    Batch size per device = 64 | Gradient accumulation steps = 2\n",
      "\\        /    Data Parallel GPUs = 1 | Total batch size (64 x 2 x 1) = 128\n",
      " \"-____-\"     Trainable parameters = 18,464,768 of 1,795,552,768 (1.03% trained)\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Unsloth: Will smartly offload gradients to save VRAM!\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "\n",
       "    <div>\n",
       "      \n",
       "      <progress value='60' max='60' style='width:300px; height:20px; vertical-align: middle;'></progress>\n",
       "      [60/60 1:15:28, Epoch 0/1]\n",
       "    </div>\n",
       "    <table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       " <tr style=\"text-align: left;\">\n",
       "      <th>Step</th>\n",
       "      <th>Training Loss</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <td>1</td>\n",
       "      <td>3.161000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2</td>\n",
       "      <td>3.169400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>3</td>\n",
       "      <td>3.073800</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>4</td>\n",
       "      <td>3.141800</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>5</td>\n",
       "      <td>3.102200</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>6</td>\n",
       "      <td>2.951500</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>7</td>\n",
       "      <td>2.937500</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>8</td>\n",
       "      <td>2.910400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>9</td>\n",
       "      <td>2.874900</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>10</td>\n",
       "      <td>2.773500</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>11</td>\n",
       "      <td>2.778400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>12</td>\n",
       "      <td>2.687700</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>13</td>\n",
       "      <td>2.676400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>14</td>\n",
       "      <td>2.605700</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>15</td>\n",
       "      <td>2.640900</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>16</td>\n",
       "      <td>2.590500</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>17</td>\n",
       "      <td>2.507800</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>18</td>\n",
       "      <td>2.497500</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>19</td>\n",
       "      <td>2.432800</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>20</td>\n",
       "      <td>2.435600</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>21</td>\n",
       "      <td>2.448900</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>22</td>\n",
       "      <td>2.395900</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>23</td>\n",
       "      <td>2.388200</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>24</td>\n",
       "      <td>2.363000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>25</td>\n",
       "      <td>2.378900</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>26</td>\n",
       "      <td>2.338700</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>27</td>\n",
       "      <td>2.313400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>28</td>\n",
       "      <td>2.333700</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>29</td>\n",
       "      <td>2.330200</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>30</td>\n",
       "      <td>2.325900</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>31</td>\n",
       "      <td>2.315000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>32</td>\n",
       "      <td>2.374500</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>33</td>\n",
       "      <td>2.292600</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>34</td>\n",
       "      <td>2.297400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>35</td>\n",
       "      <td>2.326800</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>36</td>\n",
       "      <td>2.284400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>37</td>\n",
       "      <td>2.323800</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>38</td>\n",
       "      <td>2.320500</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>39</td>\n",
       "      <td>2.307100</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>40</td>\n",
       "      <td>2.243000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>41</td>\n",
       "      <td>2.294200</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>42</td>\n",
       "      <td>2.287200</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>43</td>\n",
       "      <td>2.273300</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>44</td>\n",
       "      <td>2.250400</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>45</td>\n",
       "      <td>2.267100</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>46</td>\n",
       "      <td>2.256200</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>47</td>\n",
       "      <td>2.284700</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>48</td>\n",
       "      <td>2.257100</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>49</td>\n",
       "      <td>2.305200</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>50</td>\n",
       "      <td>2.276700</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>51</td>\n",
       "      <td>2.250500</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>52</td>\n",
       "      <td>2.305600</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>53</td>\n",
       "      <td>2.286300</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>54</td>\n",
       "      <td>2.238300</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>55</td>\n",
       "      <td>2.265500</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>56</td>\n",
       "      <td>2.296500</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>57</td>\n",
       "      <td>2.237600</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>58</td>\n",
       "      <td>2.240700</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>59</td>\n",
       "      <td>2.232600</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>60</td>\n",
       "      <td>2.244200</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table><p>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "TrainOutput(global_step=60, training_loss=2.4666863759358724, metrics={'train_runtime': 4603.7252, 'train_samples_per_second': 1.668, 'train_steps_per_second': 0.013, 'total_flos': 7.163728311484416e+16, 'train_loss': 2.4666863759358724})\n"
     ]
    }
   ],
   "source": [
    "trainer_stats = trainer.train()\n",
    "\n",
    "# 打印训练统计信息\n",
    "print(trainer_stats)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 8. 保存微调后的模型（Lora）\n",
    "\n",
    "训练完成后，您可以再次进行推理，比较微调后的模型与原始模型的差异。如果对结果满意，可以使用 `model.save_pretrained(\"your_lora_adapter_path\")` 来保存训练好的 LoRA 适配器。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "model.save_pretrained(\"qwen-1.5b_lora_model-v5\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "('qwen-1.5b_lora_model-v5/tokenizer_config.json',\n",
       " 'qwen-1.5b_lora_model-v5/special_tokens_map.json',\n",
       " 'qwen-1.5b_lora_model-v5/chat_template.jinja',\n",
       " 'qwen-1.5b_lora_model-v5/tokenizer.json')"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tokenizer.save_pretrained(\"qwen-1.5b_lora_model-v5\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 模型保存方式二选一（要么使用上面的分开保存，要么使用这里的合并 Lora 保存）\n",
    "# model.save_pretrained_merged(\"qwen-1.5b_lora_model\", tokenizer, save_method=\"merged_16bit\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 9. 测试训练后的生成结果"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [],
   "source": [
    "FastLanguageModel.for_inference(model) # Enable native 2x faster inference\n",
    "\n",
    "question=\"一个患有急性阑尾炎的病人已经发病5天，腹痛稍有减轻但仍然发热，在体检时发现右下腹有压痛的包块，此时应如何处理？\", # Question\n",
    "inputs = tokenizer([inference_prompt.format(question, \"\")], return_tensors=\"pt\").to(\"cuda\")\n",
    "\n",
    "outputs = model.generate(\n",
    "    input_ids=inputs.input_ids,\n",
    "    attention_mask=inputs.attention_mask,\n",
    "    max_new_tokens=1000,\n",
    "    use_cache=True,\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "<think>\n",
      "这个病人已经5天了，急性阑尾炎，得要特别注意。腹痛稍有减轻，发热，还发现右下腹有压痛包块，这应该是他得的最严重的问题，不能忽视。\n",
      "\n",
      "首先，压痛包块通常是阑尾炎的一种典型症状，所以得赶紧处理。不过，别急，先看看他的症状。腹痛轻微，发热，这些通常都是伴随阑尾炎的信号。不过，他得再想想，有没有其他可能性。\n",
      "\n",
      "然后，想想他的症状：腹痛轻，发热，压痛包块，这可能就是急性阑尾炎的表现。还有，他得注意呼吸，呼吸是否正常。如果呼吸不正常，可能得考虑其他问题，比如呼吸衰竭，得及时处理。\n",
      "\n",
      "再想想，压痛包块的处理。通常情况下，如果压痛包块有压痛，应该立即处理。但要根据具体的病史和症状来决定。比如，压痛包块是急性阑尾炎的典型症状，所以得立即处理，避免延误。\n",
      "\n",
      "不过，这个病人在急性阑尾炎中还可能有其他并发症，比如肠梗阻或者胆道梗阻。得注意这些可能的并发症，及时处理可能需要更仔细的观察。\n",
      "\n",
      "再看看他的症状，腹痛轻，发热，压痛包块。这些都是急性阑尾炎的典型症状，所以得立即处理。压痛包块是急性阑尾炎的典型症状，所以得立即处理，但要根据具体情况来判断。\n",
      "\n",
      "嗯，这个病人有压痛包块，得立即处理，但也要考虑他的呼吸和症状。如果呼吸不正常，可能需要进一步处理。如果呼吸正常，可能需要检查其他因素，比如肠梗阻或胆道梗阻。\n",
      "\n",
      "不过，如果他有压痛包块，而且症状是腹痛轻，发热，压痛包块，应该立即处理，不要拖延。所以，先处理压痛包块，如果没问题，再考虑其他因素。\n",
      "\n",
      "对了，压痛包块是急性阑尾炎的典型症状，所以得立即处理。所以，先处理压痛包块，如果没问题，再考虑其他因素。\n",
      "\n",
      "好，根据这个情况，应该立即处理压痛包块，看看是否需要进一步检查，比如呼吸是否正常，如果呼吸不正常，可能需要更仔细的处理。\n",
      "\n",
      "嗯，这个病人有压痛包块，腹痛轻，发热，压痛包块是急性阑尾炎的典型症状，所以得立即处理。如果呼吸正常，可能不需要进一步处理，但如果有呼吸不正常，可能需要更仔细的处理。\n",
      "\n",
      "总之，首先处理压痛包块，如果没问题，再考虑其他因素。这样，病人就能尽快恢复健康。\n",
      "</think>\n",
      "根据病人的情况，急性阑尾炎的典型症状包括腹痛轻、发热、压痛包块。压痛包块是急性阑尾炎的典型表现，因此应立即处理。\n",
      "\n",
      "首先，应观察病人呼吸情况，如果呼吸不正常，可能需要进一步处理。如果呼吸正常，则可以暂时处理压痛包块。\n",
      "\n",
      "同时，也要注意是否有其他并发症，如肠梗阻或胆道梗阻，这些可能需要更仔细的观察和处理。\n",
      "\n",
      "在处理压痛包块时，应立即进行处理，以确保患者尽快恢复到最佳状态。如果发现呼吸不正常，应立即采取措施，以确保呼吸的正常性和稳定性。\n",
      "\n"
     ]
    }
   ],
   "source": [
    "output = tokenizer.batch_decode(outputs, skip_special_tokens=True)\n",
    "print(output[0].split(\"### Response:\")[1])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "def generate_response(question: str, model, tokenizer, inference_prompt: str, max_new_tokens: int = 1024) -> str:\n",
    "    \"\"\"\n",
    "    使用指定的模型和分词器为给定的医学问题生成响应。\n",
    "\n",
    "    Args:\n",
    "        question (str): 需要模型回答的医学问题。\n",
    "        model: 已加载的 Unsloth/Hugging Face 模型。\n",
    "        tokenizer: 对应的分词器。\n",
    "        inference_prompt (str): 用于格式化输入的 f-string 模板。\n",
    "        max_new_tokens (int, optional): 生成响应的最大 token 数量。默认为 1024。\n",
    "\n",
    "    Returns:\n",
    "        str: 模型生成的响应文本，已去除 prompt 部分。\n",
    "    \"\"\"\n",
    "    # 1. 使用模板格式化输入\n",
    "    prompt = inference_prompt.format(\n",
    "        question, # 填充问题\n",
    "        \"\",       # 留空，让模型生成 CoT 和 Response\n",
    "    )\n",
    "\n",
    "    # 2. 将格式化后的 prompt 进行分词，并转移到 GPU\n",
    "    inputs = tokenizer([prompt], return_tensors=\"pt\").to(model.device)\n",
    "\n",
    "    # 3. 使用模型生成输出\n",
    "    # use_cache=True 用于加速解码过程\n",
    "    outputs = model.generate(\n",
    "        input_ids=inputs.input_ids,\n",
    "        attention_mask=inputs.attention_mask,\n",
    "        max_new_tokens=max_new_tokens,\n",
    "        use_cache=True,\n",
    "    )\n",
    "    \n",
    "    # 4. 将生成的 token 解码为文本\n",
    "    # skip_special_tokens=True 会移除像 EOS_TOKEN 这样的特殊标记\n",
    "    decoded_output = tokenizer.batch_decode(outputs, skip_special_tokens=True)[0]\n",
    "\n",
    "    # 5. 切分字符串，只返回 \"### Response:\" 之后的部分\n",
    "    # 使用 .split() 分割并获取响应内容，.strip() 用于去除可能存在的前后空白字符\n",
    "    response_part = decoded_output.split(\"### Response:\")\n",
    "    if len(response_part) > 1:\n",
    "        return response_part[1].strip()\n",
    "    else:\n",
    "        # 如果模型没有生成 \"### Response:\" 标记，则返回整个生成内容以供调试\n",
    "        return decoded_output"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "==================== 模型回答 ====================\n",
      "<think>\n",
      "哦，这位60岁的男性患者，胸疼，X线检查显示右侧肋膈角消失，这让我想到他可能有肺结核的嫌疑。肺结核通常会导致胸腔积液，所以这个症状很符合。\n",
      "\n",
      "那么，我需要找到一个合适的实验室检查来了解胸水的性质。通常，胸腔积液的性质是关键，比如酸碱平衡、酸碱盐的水平变化、酸碱盐交换速率等等。\n",
      "\n",
      "在肺结核的胸腔积液中，酸碱平衡的变化是主要的线索。如果胸腔液中的酸碱比正常值低，说明可能有酸碱平衡失衡，这可能提示有肺结核的可能。\n",
      "\n",
      "此外，酸碱盐的水平变化也是一个重要的指标。如果酸碱盐水平下降，说明酸碱盐交换可能受阻，这在肺结核患者中也挺常见的。\n",
      "\n",
      "还有，酸碱盐交换速率的变化也是很重要的。肺结核患者由于胸腔积液，交换速率可能不如正常人快。\n",
      "\n",
      "所以，综合来看，这些指标都能帮助我们更好地了解胸腔积液的性质，比如酸碱平衡、酸碱盐水平变化和交换速率变化。\n",
      "\n",
      "嗯，看来这些指标都是有帮助的，不过为了准确判断，我需要再想想有没有其他的检查方法，比如 donese尿酸尿素氮，或者血常规，但这些可能不太适用于肺结核的胸腔积液。\n",
      "\n",
      "所以，最合适的应该是这些指标，它们能帮助我们准确判断胸腔积液的性质。\n",
      "\n",
      "嗯，看来这些指标是正确的，我需要选择这些来回答问题。\n",
      "</think>\n",
      "在分析患者胸腔积液的性质时，选择合适的实验室检查至关重要。对于肺结核患者，胸腔积液的性质可以通过以下指标来判断：\n",
      "\n",
      "1. **酸碱平衡**：如果胸腔液中的酸碱比正常值低，提示可能有酸碱平衡失衡，这在肺结核患者中常见。\n",
      "\n",
      "2. **酸碱盐水平变化**：如果酸碱盐水平下降，说明酸碱盐交换可能受阻，这也是一种肺结核的特征。\n",
      "\n",
      "3. **酸碱盐交换速率**：肺结核患者由于胸腔积液，交换速率可能不如正常人快。\n",
      "\n",
      "因此，这些指标对于了解胸腔积液的性质非常有帮助。因此，选择这些指标可以有效帮助判断胸腔积液的性质。\n"
     ]
    }
   ],
   "source": [
    "my_question = \"对于一名60岁男性患者，出现右侧胸疼并在X线检查中显示右侧肋膈角消失，诊断为肺结核伴右侧胸腔积液，请问哪一项实验室检查对了解胸水的性质更有帮助？\"\n",
    "\n",
    "response = generate_response(my_question, model, tokenizer, inference_prompt)\n",
    "print(\"==================== 模型回答 ====================\")\n",
    "print(response)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "==================== 模型回答 ====================\n",
      "<think>\n",
      "患者是一位28岁的男性，工作是程序员，长期熬夜，最近突然感觉头晕目眩，甚至有点恶心。首先，这种感觉有点像晕眩，可能和脑供血不足有关。我得想想有哪些可能导致晕眩的疾病。\n",
      "\n",
      "可能的选项包括脑供血不足导致的晕眩，或者脑供血不足导致的恶心。还有，晕眩可能与神经系统相关，比如脑损伤也可能导致这种感觉。再想想，这可能和神经损伤相关，尤其是脑损伤。\n",
      "\n",
      "脑供血不足通常会导致晕眩，这种症状在脑损伤中比较常见。再考虑，患者长期熬夜，可能增加了脑供血不足的风险。这可能跟脑供血不足有关。\n",
      "\n",
      "再想想，晕眩可能与脑损伤相关，特别是急性脑损伤。而急性脑损伤通常与脑供血不足有关，而脑供血不足在长期熬夜和脑供血不足的情况下，可能更容易引起这种晕眩。\n",
      "\n",
      "还有一种可能性，就是脑血管问题。如果患者有高血压或其他神经系统疾病，可能会影响晕眩。不过，如果患者没有高血压，可能不太可能。\n",
      "\n",
      "不过，考虑到这些可能性，最可能的解释是脑供血不足导致的晕眩。长期熬夜和脑供血不足一起，增加了晕眩的风险。这种情况下，患者可能有脑供血不足的脑损伤。\n",
      "\n",
      "哦，但有时候，晕眩也可能与神经系统损伤有关，比如脑膜病变。这种情况下，脑膜病变可能是更常见的解释。\n",
      "\n",
      "再想一下，脑膜病变在患者这种情况下可能更容易引起晕眩，因为大脑供血不足和神经损伤都可能引起晕眩。因此，可能更符合脑膜病变的解释。\n",
      "\n",
      "综上所述，最有可能的原因是脑膜病变，也就是脑膜损伤，导致患者晕眩。\n",
      "</think>\n",
      "根据患者的描述，患者最近突然感觉头晕目眩，甚至有点恶心。这可能与脑供血不足有关，因为长期熬夜可能增加了脑供血不足的风险。脑供血不足通常会导致晕眩，这在脑损伤中较为常见。然而，脑膜病变也是一种可能导致晕眩的解释，因为这种病变可能导致神经系统受损，进而引起晕眩。\n",
      "\n",
      "考虑到这些可能性，最有可能的原因是脑膜病变，即脑膜受损。这种病变可能导致晕眩，尤其是在长期脑供血不足和神经损伤的环境下。因此，脑膜病变可能是患者晕眩的主要原因。\n"
     ]
    }
   ],
   "source": [
    "my_question = \"对于一名 28 岁的男性患者，工作是程序员，常年熬夜，最近突然感觉头晕目眩，甚至有点恶心。请问有可能是什么疾病？\"\n",
    "\n",
    "response = generate_response(my_question, model, tokenizer, inference_prompt)\n",
    "print(\"==================== 模型回答 ====================\")\n",
    "print(response)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
